home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Languguage OS 2
/
Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO
/
language
/
ici
/
ici.cpi
/
set.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-27
|
6KB
|
309 lines
#include "object.h"
#include "set.h"
#include "op.h"
#include "int.h"
#include "buf.h"
#include "null.h"
/*
* Find the set slot which does, or should, contain the key k.
*/
object_t **
find_set_slot(s, k)
register set_t *s;
register object_t *k;
{
register object_t **e;
e = &s->s_slots[(unsigned long)k % s->s_nslots];
while (*e != NULL)
{
if (*e == k)
return e;
if (--e < s->s_slots)
e = s->s_slots + s->s_nslots - 1;
}
return e;
}
STATIC long
mark_set(s)
register set_t *s;
{
register object_t **e;
long mem;
objof(s)->o_flags |= O_MARK;
mem = sizeof(set_t) + s->s_nslots * sizeof(object_t *);
if (s->s_nels == 0)
return mem;
for (e = &s->s_slots[s->s_nslots - 1]; e >= s->s_slots; --e)
{
if (*e != NULL)
mem += mark(*e);
}
return mem;
}
STATIC void
free_set(s)
register set_t *s;
{
if (s->s_slots != NULL)
zfree((char *)s->s_slots);
zfree((char *)s);
}
set_t *
new_set()
{
register set_t *s;
/*
* NB: there is a copy of this sequence in copy_set.
*/
if ((s = talloc(set_t)) == NULL)
return NULL;
objof(s)->o_type = &set_type;
objof(s)->o_tcode = TC_SET;
objof(s)->o_flags = 0;
objof(s)->o_nrefs = 1;
rego(s);
s->s_nels = 0;
s->s_nslots = FEW_OBJS;
/*
* Note the FEW_OBJS below is choosen to correspond with the smaller of
* the special memory lists.
*/
if ((s->s_slots = (object_t **)zalloc(FEW_OBJS*sizeof(object_t *))) == NULL)
return NULL;
memset(s->s_slots, 0, FEW_OBJS * sizeof(object_t *));
return s;
}
STATIC int
cmp_set(s1, s2)
set_t *s1;
set_t *s2;
{
register int i;
register object_t **e;
if (s1 == s2)
return 0;
if (s1->s_nels != s2->s_nels)
return 1;
e = s1->s_slots;
i = s1->s_nslots;
while (--i >= 0)
{
if (*e != NULL && *find_set_slot(s2, *e) == NULL)
return 1;
++e;
}
return 0;
}
STATIC long
hash_set(s)
set_t *s;
{
return s->s_nels;
}
STATIC object_t *
copy_set(s)
register set_t *s;
{
register set_t *ns;
if ((ns = talloc(set_t)) == NULL)
return NULL;
objof(ns)->o_type = &set_type;
objof(ns)->o_tcode = TC_SET;
objof(ns)->o_flags = 0;
objof(ns)->o_nrefs = 1;
rego(ns);
ns->s_nels = 0;
ns->s_nslots = 0;
if ((ns->s_slots = (object_t **)zalloc(s->s_nslots * sizeof(object_t *))) == NULL)
goto fail;
memcpy((char *)ns->s_slots, (char *)s->s_slots, s->s_nslots*sizeof(object_t *));
ns->s_nels = s->s_nels;
ns->s_nslots = s->s_nslots;
return objof(ns);
fail:
loose(ns);
return NULL;
}
/*
* Grow the set s so that it has twice as many slots.
*/
STATIC int
grow_set(s)
register set_t *s;
{
register object_t **e;
register object_t **oldslots;
register int i;
i = (s->s_nslots * 2 + 1) * sizeof(object_t *);
if ((e = (object_t **)zalloc(i)) == NULL)
return 1;
memset((char *)e, 0, i);
oldslots = s->s_slots;
s->s_slots = e;
i = s->s_nslots;
s->s_nslots = s->s_nslots * 2 + 1;
while (--i >= 0)
{
if (oldslots[i] != NULL)
*find_set_slot(s, oldslots[i]) = oldslots[i];
}
zfree((char *)oldslots);
return 0;
}
/*
* Remove the key from the structure.
*/
int
unassign_set(s, k)
register set_t *s;
object_t *k;
{
register object_t **sl;
register object_t **ss;
register object_t **ws; /* Wanted position. */
if (*(ss = find_set_slot(s, k)) == NULL)
return 0;
--s->s_nels;
sl = ss;
/*
* Scan "forward" bubbling up entries which would rather be at our
* current empty slot.
*/
for (;;)
{
if (--sl < s->s_slots)
sl = s->s_slots + s->s_nslots - 1;
if (*sl == NULL)
break;
ws = &s->s_slots[(unsigned long)*sl % s->s_nslots];
if
(
(sl < ss && (ws >= ss || ws < sl))
||
(sl > ss && (ws >= ss && ws < sl))
)
{
/*
* The value at sl, which really wants to be at ws, should go
* into the current empty slot (ss). Copy it to there and update
* ss to be here (which now becomes empty).
*/
*ss = *sl;
ss = sl;
}
}
*ss = NULL;
return 0;
}
/*
* Add or delete the key k from the set based on the value of v.
*/
STATIC int
assign_set(s, k, v)
set_t *s;
register object_t *k;
register object_t *v;
{
register object_t **e;
if (objof(s)->o_flags & O_ATOM)
{
error = "attempt to modify an atomic set";
return 1;
}
if (isfalse(v))
{
return unassign_set(s, k);
}
else
{
e = find_set_slot(s, k);
if (*e == NULL)
{
if (++s->s_nels >= s->s_nslots - s->s_nslots / 5)
{
/*
* This set has become 80% full. Grow it.
*/
if (grow_set(s))
return 1;
e = find_set_slot(s, k);
}
*e = k;
}
}
return 0;
}
STATIC object_t *
fetch_set(s, k)
set_t *s;
register object_t *k;
{
return *find_set_slot(s, k) == NULL ? objof(&o_null) : objof(o_one);
}
type_t set_type =
{
mark_set,
free_set,
hash_set,
cmp_set,
copy_set,
assign_set,
fetch_set,
"set"
};
/*
* Return 1 if a is a subset of b, else 0.
*/
int
set_issubset(a, b) /* a is a subset of b */
set_t *a;
set_t *b;
{
register object_t **sl;
register int i;
for (sl = a->s_slots, i = 0; i < a->s_nslots; ++i, ++sl)
{
if (*sl == NULL)
continue;
if (*find_set_slot(b, *sl) == NULL)
return 0;
}
return 1;
}
/*
* Return 1 if a is a proper subset of b, else 0. That is, is a subset
* and not equal.
*/
int
set_ispropersubset(a, b) /* a is a proper subset of b */
set_t *a;
set_t *b;
{
return a->s_nels < b->s_nels && set_issubset(a, b);
}